using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace Drill.Core.Utilities
{
    [TestFixture]
    public class ValidationUtilityTests
    {
        private const string TestParamName = "testStringParam";
        private static readonly char[] _whitespaceChars = new[] { ' ', '\f', '\n', '\r', '\t' };

        [Category("UnitTest")]
        [Test]
        [TestCaseSource("TestCasesForCanGetArgumentExceptionForStringIsEmpty")]
        public bool CanGetArgumentExceptionForStringIsEmpty(string value, string paramName)
        {
            // This test returns true if the argument exception returned 
            // is not null, contains the text, "string cannot be empty," 
            // and is of type System.ArgumentException.

            ArgumentException argumentException = 
                ValidationUtility.GetArgumentExceptionForStringIsEmpty(value, paramName);

            return 
                argumentException != null
             && argumentException.Message.Equals("The testStringParam parameter is not in the correct format. The string cannot be empty.\r\nParameter name: testStringParam")
             && argumentException.GetType().Equals(typeof(ArgumentException))
                       ? true
                       : false;
        }

        public static IEnumerable<TestCaseData> TestCasesForCanGetArgumentExceptionForStringIsEmpty
        {
            get
            {
                yield return new TestCaseData(null, null).Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, "").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, " ").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, TestParamName).Returns(false);
                yield return new TestCaseData("", TestParamName).Returns(true);

                // Generate whitespace values to test.
                for (int i = 1; i < 11; i++)
                {
                    foreach (char whitespaceChar in _whitespaceChars)
                    {
                        string whitespacePath = new string(whitespaceChar, i);
                        yield return new TestCaseData(whitespacePath, TestParamName).Returns(false);
                    }
                }

                yield return new TestCaseData("a", TestParamName).Returns(false);
                yield return new TestCaseData("ab", TestParamName).Returns(false);
                yield return new TestCaseData("abc", TestParamName).Returns(false);
            }
        }

        [Category("UnitTest")]
        [Test]
        [TestCaseSource("TestCasesForCanGetArgumentExceptionForStringIsNull")]
        public bool CanGetArgumentExceptionForStringIsNull(string value, string paramName)
        {
            // This test returns true if the argument exception returned 
            // is not null, contains the text, "string cannot be empty," 
            // and is of type System.ArgumentNullException.

            ArgumentException argumentException =
                ValidationUtility.GetArgumentExceptionForStringIsNull(value, paramName);

            return
                argumentException != null
             && argumentException.Message.Equals("The testStringParam parameter cannot be null.\r\nParameter name: testStringParam")
             && argumentException.GetType().Equals(typeof(ArgumentNullException))
                       ? true
                       : false;
        }

        public static IEnumerable<TestCaseData> TestCasesForCanGetArgumentExceptionForStringIsNull
        {
            get
            {
                yield return new TestCaseData(null, null).Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, "").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, " ").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, TestParamName).Returns(true);
                yield return new TestCaseData("", TestParamName).Returns(false);

                // Generate whitespace values to test.
                for (int i = 1; i < 11; i++)
                {
                    foreach (char whitespaceChar in _whitespaceChars)
                    {
                        string whitespacePath = new string(whitespaceChar, i);
                        yield return new TestCaseData(whitespacePath, TestParamName).Returns(false);
                    }
                }

                yield return new TestCaseData("a", TestParamName).Returns(false);
                yield return new TestCaseData("ab", TestParamName).Returns(false);
                yield return new TestCaseData("abc", TestParamName).Returns(false);
            }
        }

        [Category("UnitTest")]
        [Test]
        [TestCaseSource("TestCasesForCanGetArgumentExceptionForStringContainsOnlyWhitespace")]
        public bool CanGetArgumentExceptionForStringContainsOnlyWhitespace(string value, string paramName)
        {
            // This test returns true if the argument exception returned 
            // is not null, contains the text, "string cannot be empty," 
            // and is of type System.ArgumentException.

            ArgumentException argumentException =
                ValidationUtility.GetArgumentExceptionForStringContainsOnlyWhitespace(value, paramName);

            return
                argumentException != null
             && argumentException.Message.Equals("The testStringParam parameter is not in the correct format. The string cannot contain only whitespace characters.\r\nParameter name: testStringParam")
             && argumentException.GetType().Equals(typeof(ArgumentException))
                       ? true
                       : false;
        }

        public static IEnumerable<TestCaseData> TestCasesForCanGetArgumentExceptionForStringContainsOnlyWhitespace
        {
            get
            {
                yield return new TestCaseData(null, null).Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, "").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, " ").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, TestParamName).Returns(false);
                yield return new TestCaseData("", TestParamName).Returns(false);

                // Generate whitespace values to test.
                for (int i = 1; i < 11; i++)
                {
                    foreach (char whitespaceChar in _whitespaceChars)
                    {
                        string whitespacePath = new string(whitespaceChar, i);
                        yield return new TestCaseData(whitespacePath, TestParamName).Returns(true);
                    }
                }

                yield return new TestCaseData("a", TestParamName).Returns(false);
                yield return new TestCaseData("ab", TestParamName).Returns(false);
                yield return new TestCaseData("abc", TestParamName).Returns(false);
            }
        }

        [Category("UnitTest")]
        [Test]
        [TestCaseSource("TestCasesForCanGetArgumentExceptionForStringIsNullOrIsEmptyOrContainsOnlyWhitespace")]
        public bool CanGetArgumentExceptionForStringIsNullOrIsEmptyOrContainsOnlyWhitespace(string value, string paramName)
        {
            // This test returns true if the argument exception returned 
            // is not null, contains the text, "string cannot be empty," 
            // and is of type System.ArgumentException.

            ArgumentException argumentException =
                ValidationUtility.GetArgumentExceptionForStringIsNullOrIsEmptyOrContainsOnlyWhitespace(value, paramName);

            return
                argumentException != null
             && argumentException.Message.Contains("Parameter name: testStringParam")
             && (argumentException.GetType().Equals(typeof(ArgumentException)) || argumentException.GetType().Equals(typeof(ArgumentNullException)))
                       ? true
                       : false;
        }

        public static IEnumerable<TestCaseData> TestCasesForCanGetArgumentExceptionForStringIsNullOrIsEmptyOrContainsOnlyWhitespace
        {
            get
            {
                yield return new TestCaseData(null, null).Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, "").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, " ").Throws(typeof(ArgumentException));
                yield return new TestCaseData(null, TestParamName).Returns(true);
                yield return new TestCaseData("", TestParamName).Returns(true);

                // Generate whitespace values to test.
                for (int i = 1; i < 11; i++)
                {
                    foreach (char whitespaceChar in _whitespaceChars)
                    {
                        string whitespacePath = new string(whitespaceChar, i);
                        yield return new TestCaseData(whitespacePath, TestParamName).Returns(true);
                    }
                }

                yield return new TestCaseData("a", TestParamName).Returns(false);
                yield return new TestCaseData("ab", TestParamName).Returns(false);
                yield return new TestCaseData("abc", TestParamName).Returns(false);
            }
        }
    }
}